package com.ilink.ilinkcommon.service.impl.oss;

import com.ilink.ilinkcommon.service.oss.MinioService;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import io.minio.*;
import io.minio.messages.Item;
import io.minio.http.Method;
import io.minio.Result;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.InputStream;

@Slf4j
@Service
public class MinioServiceImpl implements MinioService {

    private final MinioClient minioClient;

    @Value("${ilink.minio.url}")
    private String minioUrl;

    @Value("${ilink.minio.bucketName}")
    private String bucketName;

    // 支持的文件扩展名，可以根据需要添加其他格式
    private final List<String> fileExtensions = Arrays.asList("pdf", "docx", "xlsx", "md", "txt", "zip", "tar");

    //  支持的图片拓展名
//    private final List<String> imageExtensions = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp", "tiff", "webp");
    private final List<String> imageExtensions = Arrays.asList("jpg", "jpeg", "png");

    //  支持的icon拓展名
    private final List<String> iconExtensions = Arrays.asList("svg", "jpeg", "png");

    private final List<String> StudyTreeExtensions = Arrays.asList("mp4", "jpg", "png");

    public MinioServiceImpl(@Value("${ilink.minio.url}") String url,
        @Value("${ilink.minio.accessKey}") String accessKey,
        @Value("${ilink.minio.secretKey}") String secretKey) {
        this.minioClient = MinioClient.builder()
            .endpoint(url)
            .credentials(accessKey, secretKey)
            .build();
    }

    @Override
    // 上传单个文件到MinIO的方法
    public String uploadSingleFile(String folder, String fileName, MultipartFile file) {
        try {
            // 构造目标文件路径
            String objectName = folder + "/" + fileName;

            // 上传文件到 MinIO
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build()
            );

            log.info("文件 '{}' 上传到 '{}' 成功.", objectName, bucketName);

            // 返回文件的 URL
            return minioUrl + "/" + bucketName + "/" + objectName;
        } catch (Exception e) {
            log.error("上传文件到MinIO时遇到错误：", e);
            return null;
        }
    }


    // 根据后缀遍历生成预签名 URL
    @Override
    public String generatePresignedUrlWithExtension(String objectPath, String bucketName) {
        // 遍历所有支持的后缀名，生成预签名 URL
        for (String ext : imageExtensions) {
            String objectWithExtension = objectPath + "." + ext;
            try {
                return generatePresignedUrl(objectWithExtension, bucketName);
            } catch (Exception e) {
                // 失败时继续尝试下一个后缀
                log.warn("Failed to generate URL for {}. Trying next extension.", objectWithExtension, e);
            }
        }
        log.error("Failed to generate presigned URL for object with any supported extension.");
        return null;  // 如果没有生成成功，返回 null
    }

    // 直接生成预签名 URL
    @Override
    public String generatePresignedUrl(String objectName, String bucketName) {
        try {
            // 获取预签名 URL
            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .method(Method.GET)
                .expiry(24, TimeUnit.HOURS)  // URL有效期设置为24小时
                .build();

            // 返回预签名 URL
            return minioClient.getPresignedObjectUrl(args);
        } catch (Exception e) {
            log.error("生成预签名 URL 时出错：", e);
            return null;  // 如果生成失败，返回 null
        }
    }

    /**
     * 上传文件到指定桶
     * @param file 文件
     * @param bucketName 桶名
     * @param objectName 对象名
     * @return 是否上传成功
     */
    @Override
    public boolean uploadBucketFile(MultipartFile file, String bucketName, String objectName) {
        try {
            if (file.isEmpty()) {
                log.error("上传文件为空");
                return false;
            }

            // 检查桶是否存在，不存在则创建
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }

            // 上传文件
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build()
            );

            log.info("上传指定桶成功 {} 文件名 {}", bucketName, objectName);
            return true;
        } catch (Exception e) {
            log.error("上传文件到Minio失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 获取指定桶中文件的URL
     * @param bucketName 桶名
     * @param objectName 对象名
     * @return 文件URL
     */
    @Override
    public String getBucketFileUrl(String bucketName, String objectName) {
        try {
            // 检查参数
            if (bucketName == null || bucketName.isEmpty()) {
                throw new IllegalArgumentException("从Minio生成URL时bucketName不可为空");
            }
            if (objectName == null || objectName.isEmpty()) {
                throw new IllegalArgumentException("从Minio生成URL时objectName不可为空");
            }

            // 检查对象是否存在
            try {
                minioClient.statObject(
                    StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()
                );
            } catch (Exception e) {
                log.error("{}不存在，无法得到URL {}", bucketName, objectName);
                return null;
            }

            // 生成URL，设置过期时间为24小时
            String url = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(24, TimeUnit.HOURS)
                    .build()
            );

            log.info("根据桶名生成签名 {}", url);
            String newUrl = url.replace("http://10.3.244.23:19000/", "https://ilink.bupt.edu.cn/minio/");
            return newUrl;
        } catch (Exception e) {
            log.error("Minio无法获取指定对象URL: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从指定桶中删除文件
     * @param bucketName 桶名
     * @param path 路径
     * @param fileName 文件名
     * @return 是否删除成功
     */
    @Override
    public boolean deleteBucketFile(String bucketName, String path, String fileName) {
        if (!path.endsWith("/")) {
            path += "/";
        }
        String objectName = path + fileName;
        
        try {
            // 删除对象
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build()
            );
            
            log.info("删除Minio文件{}时成功", objectName);
            return true;
        } catch (Exception e) {
            log.error("删除Minio文件失败：{}，错误信息：{}", fileName, e.getMessage());
            return false;
        }
    }

    /**
     * @Author ZhangBo
     * @Description 删除指定对象
     * @Date 17:01 2025/1/20
     * @Param [bucketName, objectName]
     * @return boolean
     **/
    @Override
    public boolean deleteFile(String bucketName, String objectName){
        try {
            // 删除对象
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build()
            );

            log.info("删除Minio对象{}时成功", objectName);
            return true;
        } catch (Exception e) {
            log.error("删除Minio对象失败：{}，错误信息：{}", objectName, e.getMessage());
            return false;
        }
    }

    @Override
    public boolean deleteDirectory(String bucketName, String directory){
// 设置安全检查，避免删除整个bucket内的文件
        if (Objects.equals(directory, "") || directory == null || Objects.equals(directory, "/")) {
            return false;
        }

        try {
            do {
                // List objects in directory using MinIO API
                Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(directory)
                        .recursive(true)
                        .build()
                );

                // Delete each object
                for (Result<Item> result : results) {
                    Item item = result.get();
                    minioClient.removeObject(
                        RemoveObjectArgs.builder()
                            .bucket(bucketName)
                            .object(item.objectName())
                            .build()
                    );
                }

            } while (false); // MinIO handles pagination internally
            log.info("删除Minio文件夹{}时成功.",directory);
            return true;
        } catch (com.aliyun.oss.OSSException e) {
            // 处理特定的OSS异常，并记录日志
            if ("RequestRateTooHigh".equals(e.getErrorCode())) {
                log.error("请求速率过高，删除目录失败：{}", directory);
            } else {
                log.error("Minio异常，删除目录失败：{}，错误信息：{}", directory, e.getMessage(), e);
            }
            return false;
        } catch (Exception e) {
            log.error("未知异常，删除目录失败：{}，错误信息：{}", directory, e.getMessage(), e);
            return false;
        }
    }

    // 从minio下载后上传到指定路径
    @Override
    public boolean downloadAndUpload(String bucketName, String fileUrl, String objectName) {
        try {
            // 从临时URL下载文件
            URL url = new URL(fileUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            InputStream inputStream = connection.getInputStream();

            // 上传文件到MinIO
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(inputStream, connection.getContentLength(), -1)
                    .contentType(connection.getContentType())
                    .build()
            );

            log.info("上传到MinIO成功，文件名: {}", objectName);
            return true;
        } catch (Exception e) {
            log.error("上传文件到MinIO失败：{}，错误信息：{}", objectName, e.getMessage());
            return false;
        }
    }

}
